/* FormView.h
Michael Zahniser, 01/08/09

Header file for the FormView class, which represents a form that the user fills out.
A form can have text fields, numeric fields, and radio buttons.

A form may be modal or modeless. If it is modal, it captures all events except for
clicks outside its area; to capture _all_ events, the form should therefore fill the
whole window. It will draw itself as a box centered in the area allowed to it.

If a form is modeless, by default pressing <RETURN> will call the callback but _not_
close the form. It can be closed in the callback if necessary.
*/

#ifndef __MZ_FORM_VIEW_H__
#define __MZ_FORM_VIEW_H__

#include "View.h"
#include "Font.h"
#include "_common/Callback.h"

#include <list>

using std::list;



class FormView : public View {
public:
	typedef CallbackT<const FormView &> Callback;


public:
	FormView(const string &title, bool isModal = true);

	// Set the callback for successful completion of the form.
	void SetCallback(Callback &callback);

	// Clear all fields, including the title.
	void Clear();
	// Add fields.
	void AddTitle(const string &title);
	void AddField(const string &label, const string &text, int min = 0, int max = 0);
	// Add a radio button. Contiguous groups of radio buttons are linked together. To
	// create groups that aren't linked, you need to put a Title or Field between them.
	void AddOption(const string &label, bool isChecked = false);

	// Get the value of the field with the given label.
	const string &ValueOf(const string &label) const;
	// Get the value of the selected field.
	const string &ValueOfSelection() const;


protected:
	// Initialize a view, given the command line arguments for the program.
	// If the view cannot be initialized, this function should return false.
	// NOTE: SDL may not be initialized yet when a View's constructor is called,
	// so all initialization using SDL should be done here instead.
	virtual bool Initialize(const Surface &surface);

	// Handle an event. If the event involves (x, y) coordinates, they have been
	// translated such that (0, 0) is the top left corner of this View.
	// This function should return false if this view does not support the given
	// event and wants other views to have a chance to handle it.
	virtual bool Handle(const SDL_Event &event);

	// Draw the view in the given surface. The surface is passed as a (shallow)
	// copy so that it is impossible for derived classes to modify View::surface
	// to point to anything other than what Interface assigns to it.
	virtual void Draw(Surface surface) const;


private:
	class Element {
	public:
		Element(const string &label, const string &text, int min = 0, int max = 0)
			: label(label), min(min), max(max), text(text) {}

		string Constraint() const;
		bool Validate() const;

		const string label;
		const int min;
		const int max;
		string text;
	};


private:
	list<Element> elements;
	list<Element>::iterator currentField;
	int cursor;

	Font font;

	Callback *callback;

	// If a form is modal, it is displayed in a centered box and it captures all events.
	bool isModal;


private:
	static const int BORDER = 4;
	static const int PAD = 4;
	static const int MIN_FIELD_WIDTH = 120;
	static const int BOX_SIZE = 8;
};

#endif
